#include <Globals.h>
#include <ProcessManager.h>
#include <Process.h>
#include <resource.h>
#include <File.h>
#include <Directory.h>
#include <signal.h>
#include <MonitorDriver.h>

extern char **environ;
int    errno   = 0;

extern "C" void *malloc(u32int);
extern "C" void free(void *);
extern "C" void *umalloc(u32int);
extern "C" void ufree(void *);
extern "C" int open(char*, int, int);
extern "C" int write(int, void*, int);
extern "C" void _exit(int);

// Required to get G++ to link without libstdc++
void *__gxx_personality_v0 = NULL;
//void *_Unwind_Resume = NULL;

u32int _process;
Address _currentKernelStack;

extern int main(char,char**);

void *operator new(size_t size)
{
  return ::malloc(size);
}

void *operator new[](size_t size)
{
  return ::malloc(size);
}

void operator delete(void *p)
{
  free(p);
}

void operator delete[](void *p)
{
  free(p);
}

class SignalHandler : public Callable
{
public:
  void callSignal(int sig)
  {
    // Newlib is retarded. After raise()ing successfully it deletes the signal handler,
    // defaulting to SIG_DFL. Why? I have no idea. Here is a stupendous workaround though...
    typedef void (*sigfunc_t)(int);
    // Take a copy of the handler, unfortunately replacing it with NULL.
    sigfunc_t handler = signal(sig, (sigfunc_t)NULL);
    // Reinstall the handler.
    signal(sig, handler);
    // Call it.
    raise(sig);
    // Reinstall the handler again after it is destroyed by raise().
    signal(sig, handler);
  }
};
extern "C" void _init_signal(void);
extern "C" void _premain(char **argv, char **env)
{

  u32int processManager = requestResource("ProcessManager");
  _process = callResource(processManager, ProcessManager_IF::getProcess, -1);
  
  _init_signal();
  
  SignalHandler *sigHandler = new SignalHandler();
  u32int sigResource = createResource((Callable*)sigHandler);
  addFunction(sigResource, (Resource::Call1)&SignalHandler::callSignal, 0);
  callResource(_process, Process_IF::initialiseSignals, sigResource);
  
  // Does stdin exist?
  if (!callResource(_process, Process_IF::getFileDescriptor, 0))
  {
    // Create it.
    open((char*)"/dev/tty", 0, 0);
    // Assume also that stdout, stderr don't exist either.
    open((char*)"/dev/tty", 0, 0);
    open((char*)"/dev/tty", 0, 0); // stderr should be open for reading and writing (POSIX)
  }

  // Count how many arguments we have, to give to main.
  char **iterator = argv;
  char argc = 0;
  while (*iterator)
  {
    iterator++;
    argc++;
  }
  
  environ = env;

  //_currentKernelStack = _process->getKernelStack();

  // Note the use of int as opposed to u32int is deliberate here.
  // Depends on the architecture.
  int retVal = main(argc, argv);
  _exit(retVal);
  // Should never get here.
}

